/**
 * Copyright (c) 2018-2028, Chill Zhuang 庄骞 (smallchill@163.com).
 * <p>
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package org.springblade.modules.order.controller;

import io.swagger.v3.oas.annotations.tags.Tag;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import lombok.AllArgsConstructor;
import jakarta.validation.Valid;

import lombok.extern.slf4j.Slf4j;
import org.springblade.core.log.exception.ServiceException;
import org.springblade.core.mp.support.Condition;
import org.springblade.core.mp.support.Query;
import org.springblade.core.tool.api.R;
import org.springblade.core.tool.utils.Func;
import org.springblade.modules.commodity.entity.Commodity;
import org.springblade.modules.order.entity.OrderRefund;
import org.springblade.modules.orderprocess.entity.OrderProcess;
import org.springblade.modules.orderprocess.service.IOrderProcessService;
import org.springblade.modules.pay.constant.ProcessStatus;
import org.springblade.modules.pay.constant.VerifyStatus;
import org.springblade.modules.pay.service.WxPayService;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.bind.annotation.RequestParam;
import com.baomidou.mybatisplus.core.metadata.IPage;
import org.springblade.modules.order.entity.Order;
import org.springblade.modules.order.vo.OrderVO;
import org.springblade.modules.order.wrapper.OrderWrapper;
import org.springblade.modules.order.service.IOrderService;
import org.springblade.core.boot.ctrl.BladeController;

import java.math.BigDecimal;
import java.util.Date;
import java.util.Objects;

import static org.springblade.modules.pay.controller.WxPayController.getOrderNum;

/**
 * 订单表 控制器
 *
 * @author Blade
 * @since 2024-09-02
 */
@RestController
@AllArgsConstructor
@RequestMapping("/order")
@Tag(name = "订单表", description = "订单表接口")
@Slf4j
public class OrderController extends BladeController {

	private IOrderService orderService;
	private final IOrderProcessService orderProcessService;

	private final WxPayService wxPayService;
	/**
	 * 详情
	 */
	@GetMapping("/detail")
	@ApiOperationSupport(order = 1)
	@Operation(summary = "详情", description = "传入order")
	public R<Order> detail(Order order) {
		return R.data(orderService.selectById(order.getId()));
	}

	/**
	 * 分页 订单表
	 */
	@GetMapping("/list")
	@ApiOperationSupport(order = 2)
	@Operation(summary = "分页", description = "传入order")
	public R<IPage<OrderVO>> list(Order order, Query query) {
		IPage<Order> pages = orderService.page(Condition.getPage(query), Condition.getQueryWrapper(order));
		return R.data(OrderWrapper.build().pageVO(pages));
	}


	/**
	 * 自定义分页 订单表
	 */
	@GetMapping("/page")
	@ApiOperationSupport(order = 3)
	@Operation(summary = "分页", description = "传入order")
	public R<IPage<OrderVO>> page(OrderVO order, Query query) {
		IPage<OrderVO> pages = orderService.selectOrderPage(Condition.getPage(query), order);
		return R.data(pages);
	}

	/**
	 * 新增 订单表
	 */
	@PostMapping("/save")
	@ApiOperationSupport(order = 4)
	@Operation(summary = "新增", description = "传入order")
	public R save(@Valid @RequestBody Order order) {
		return R.status(orderService.save(order));
	}

	/**
	 * 修改 订单表
	 */
	@PostMapping("/update")
	@ApiOperationSupport(order = 5)
	@Operation(summary = "修改", description = "传入order")
	public R update(@RequestBody Order order) {
		return R.status(orderService.updateById(order));
	}

	/**
	 * 新增或修改 订单表
	 */
	@PostMapping("/submit")
	@ApiOperationSupport(order = 6)
	@Operation(summary = "新增或修改", description = "传入order")
	public R submit(@Valid @RequestBody Order order) {
		return R.status(orderService.saveOrUpdate(order));
	}


	/**
	 * 删除 订单表
	 */
	@PostMapping("/remove")
	@ApiOperationSupport(order = 7)
	@Operation(summary = "逻辑删除", description = "传入ids")
	public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String ids) {
		return R.status(orderService.deleteLogic(Func.toLongList(ids)));
	}


	/**
	 * 获取我的订单
	 *
	 * @param order 秩序
	 * @param query 查询
	 * @return {@link R }<{@link IPage }<{@link OrderVO }>>
	 */
	@GetMapping("/getMyOrder")
	@ApiOperationSupport(order = 3)
	@Operation(summary = "分页", description = "传入order")
	public R<IPage<OrderVO>> getMyOrder(OrderVO order, Query query) {
		IPage<OrderVO> pages = orderService.getMyOrder(Condition.getPage(query), order);
		return R.data(pages);
	}


	/**
	 * 核销订单
	 *
	 * @param order 秩序
	 * @return {@link R }
	 */
	@PostMapping("/verify")
	@ApiOperationSupport(order = 6)
	@Operation(summary = "核销订单", description = "传入order")
	public R verify(@RequestBody Order order) {
		if (Func.isEmpty(order)) {
			throw new ServiceException("订单不能为空");
		}
		if (Func.isEmpty(order.getId())) {
			throw new ServiceException("订单id不能为空");
		}
		order = orderService.getById(order);
		if (Func.isEmpty(order.getPayStatus()) || order.getPayStatus() != 1) {
			throw new ServiceException("订单未支付无法进行核销");
		}
		if (Objects.equals(order.getVerifyStatus(), VerifyStatus.VERIFIED.getStatus()) || Func.isNotEmpty(order.getVerifyTime())){
			throw  new ServiceException("订单已核销，请勿重复操作");
		}
		order.setVerifyStatus(VerifyStatus.VERIFIED.getStatus());
		order.setVerifyTime(new Date());
		boolean b = orderService.updateById(order);
		if (b) {
			OrderProcess orderProcess = new OrderProcess();
			orderProcess.setOrderId(order.getId());
			orderProcess.setFillTime(new Date());
			orderProcess.setAction(ProcessStatus.VERIFIED.getDescription());
			orderProcessService.save(orderProcess);
		}

		return R.status(b);
	}

	/**
	 * 归还订单
	 *
	 * @param order 秩序
	 * @return {@link R }
	 */
	@PostMapping("/returnBack")
	@ApiOperationSupport(order = 6)
	@Operation(summary = "归还订单", description = "传入order")
	public R returnBack(@RequestBody Order order) {
		if (Func.isEmpty(order)) {
			throw new ServiceException("订单不能为空");
		}
		if (Func.isEmpty(order.getId())) {
			throw new ServiceException("订单id不能为空");
		}
		order = orderService.getById(order);
		if (Func.isEmpty(order.getPayStatus()) || order.getPayStatus() != 1) {
			throw new ServiceException("订单未支付无法进行核销");
		}
		order.setVerifyStatus(VerifyStatus.REFUNDED.getStatus());
		order.setReturnTime(new Date());
		boolean b = orderService.updateById(order);
		if (b) {
			OrderProcess orderProcess = new OrderProcess();
			orderProcess.setOrderId(order.getId());
			orderProcess.setFillTime(new Date());
			orderProcess.setAction(ProcessStatus.RETURNABLE.getDescription());
			orderProcessService.save(orderProcess);
		}
		return R.status(b);
	}


	/**
	 * 取消订单
	 *
	 * @param order 秩序
	 * @return {@link R }
	 */
	@PostMapping("/cancel")
	@ApiOperationSupport(order = 6)
	@Operation(summary = "取消订单", description = "传入order")
	@Transactional(rollbackFor = Exception.class)
	public R cancel(@RequestBody Order order) {
		if (Func.isEmpty(order)) {
			throw new ServiceException("订单不能为空");
		}
		if (Func.isEmpty(order.getId())) {
			throw new ServiceException("订单id不能为空");
		}
		order = orderService.selectById(order.getId());
		if (!order.getVerifyStatus().equals(VerifyStatus.CREATED.getStatus())) {
			throw new ServiceException("订单已核销无法取消");
		}
		OrderRefund orderRefund = new OrderRefund();
		orderRefund.setOrderId(order.getId());
		orderRefund.setRefundNum(getOrderNum());
		BigDecimal reduce = order.getCommodityList().stream().map(Commodity::getPrice).reduce(BigDecimal.ZERO, BigDecimal::add);
		log.info("退款金额：{}",reduce);
		orderRefund.setRefundPrice(reduce);
		wxPayService.refund(orderRefund);
//		order.setVerifyStatus(VerifyStatus.REFUNDED.getStatus());
		order.setReturnTime(new Date());
		order.setPayStatus(4);
		boolean b = orderService.updateById(order);
		if (b) {
			OrderProcess orderProcess = new OrderProcess();
			orderProcess.setOrderId(order.getId());
			orderProcess.setFillTime(new Date());
			orderProcess.setAction(ProcessStatus.CANCEL.getDescription());
			orderProcessService.save(orderProcess);
		}
		return R.status(b);
	}
}
